package edu.ntu.cloudroid.xacml.obligation;

import java.net.URI;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;


import com.sun.xacml.Obligation;
import com.sun.xacml.attr.BooleanAttribute;
import com.sun.xacml.attr.DoubleAttribute;
import com.sun.xacml.attr.IntegerAttribute;
import com.sun.xacml.attr.StringAttribute;
import com.sun.xacml.ctx.Attribute;
import com.sun.xacml.ctx.RequestCtx;
import com.sun.xacml.ctx.Subject;

import edu.ntu.cloudroid.model.IDs;
import edu.ntu.cloudroid.model.data.AbstractData;
import edu.ntu.cloudroid.model.data.DetachedData;
import edu.ntu.cloudroid.model.data.LocationData;
import edu.ntu.cloudroid.model.data.VitalSignData;
import edu.ntu.cloudroid.model.data.VitalSignInfo;
import edu.ntu.cloudroid.model.function.similar.ISimilarFunc;
import edu.ntu.cloudroid.model.function.stats.IDataStats;
import edu.ntu.cloudroid.model.policy.SimpleFiltering;
import edu.ntu.cloudroid.model.profile.ProfileData;
import edu.ntu.cloudroid.server.RequestServlet;
import edu.ntu.cloudroid.server.backendservice.DataService;
import edu.ntu.cloudroid.server.backendservice.FriendService;
import edu.ntu.cloudroid.xacml.Utilities;
import edu.ntu.cloudroid.xacml.XACMLException;
import edu.ntu.cloudroid.xacml.XACMLStrings;

/**
 * Simple statistic (summary). Basic functions are most frequent location, max,
 * min, count, etc.
 * 
 */
public class SimilarityObligation implements ObligationHandle {

	@Override
	public List<DetachedData> processObligation(ProfileData subject,
			ProfileData resource, RequestCtx requestCtx, Obligation o)
			throws Exception {
		List<Attribute> assignments = o.getAssignments();
		int functionId = 0;
		int colIdx = 0;
		int granularity = 0;
		double range = 0;
		boolean isLatestData = false;

		for (Attribute a : assignments) {
			if (a.getId().equals(
					new URI(XACMLStrings.ATTR_Similarity_FunctionId))) {
				IntegerAttribute attr = (IntegerAttribute) a.getValue();
				functionId = (int) attr.getValue();
			} else if (a.getId().equals(
					new URI(XACMLStrings.ATTR_Filtering_ColumnIdx))) {
				IntegerAttribute attr = (IntegerAttribute) a.getValue();
				colIdx = (int) attr.getValue();
			} else if (a.getId().equals(new URI(XACMLStrings.ATTR_Granularity))) {
				IntegerAttribute attr = (IntegerAttribute) a.getValue();
				granularity = (int) attr.getValue();
			} else if (a.getId().equals(
					new URI(XACMLStrings.ATTR_Similarity_Range))) {
				DoubleAttribute attr = (DoubleAttribute) a.getValue();
				range = (int) attr.getValue();
			} else if (a.getId().equals(new URI(XACMLStrings.ATTR_GetLatest))) {
				BooleanAttribute attr = (BooleanAttribute) a.getValue();
				isLatestData = attr.getValue();
			}
		}
		return this.evaluateStats(subject, resource, requestCtx, colIdx,
				IDs.getSimilarityFunction(functionId), granularity, range, isLatestData);
	}

	private List<DetachedData> evaluateStats(ProfileData subject,
			ProfileData resource, RequestCtx requestCtx, int colIdx,
			ISimilarFunc func, int granularity, double range, boolean isLatest)
			throws Exception {
		Date latestTimestamp = FriendService.getFriendTimeStamp(resource.getEmailAddress(),
				subject.getEmailAddress());
		List<DetachedData> list = new ArrayList<DetachedData>();	
		List<AbstractData> allData = new ArrayList<AbstractData>();  
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
		sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
		latestTimestamp = sdf.parse("2001-01-01 00:00");
		long start = System.currentTimeMillis();
		if (!isLatest)				
			allData = DataService.getData(resource, latestTimestamp,
					resource.getDataId());		
		else{
			System.out.println("********Resource ID = "+resource.getEmailAddress());
			AbstractData ad = DataService.getLatestData(resource, resource.getDataId());
			if (ad.getTimestamp().after(latestTimestamp))
				allData.add(ad);			
		}
		long end = System.currentTimeMillis();		
		if (allData.size() > 0) {
			
			Date maxDate = allData.get(0).getTimestamp();
			AbstractData dataFromRequest = ((AbstractData) DataService
					.getAbstractDataObject(resource.getDataId()))
					.getDataFromRequest(requestCtx);
			boolean gotSimilarData = false;
			for (AbstractData ad : allData){
				if (func.isSimilar(ad, dataFromRequest, colIdx, granularity,
						range)){
					list.add(ad.detach(colIdx));
					if (ad.getTimestamp().after(maxDate)){
						maxDate = ad.getTimestamp();
					}
					gotSimilarData = true;
				}
				
			}
			//RequestServlet.logger.info("Updating friend timestamp, ndata ="+allData.size());
			FriendService.delayTimestampUpdate(resource.getEmailAddress(),
					subject.getEmailAddress(), maxDate);
		}
				
		return list;
	}	
}
